#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

sem_t chops[5];
char ph[5] = {'A', 'B', 'C', 'D', 'E'};

void * eat1(void * arg){
    int ph_no = *(int *)arg;
    int count = 0;
    printf("%c preparing \n", ph[ph_no]);
    while(count < 5){
        sleep(rand()%5);
        if(ph_no % 2){
            sem_wait(&chops[(ph_no+1)%5]);
            // printf("Ph-%c get chop %d \n", ph[ph_no], (ph_no+1)%5);
            sem_wait(&chops[ph_no]);
            // printf("Ph-%c get chop %d \n", ph[ph_no], ph_no);
        }else{
            sem_wait(&chops[ph_no]);
            // printf("Ph-%c get chop %d \n", ph[ph_no], ph_no);
            sem_wait(&chops[(ph_no + 1)%5]);
            // printf("Ph-%c get chop %d \n", ph[ph_no], (ph_no+1)%5);
        }
        printf("Ph-%c eating ... \n", ph[ph_no]);
        sem_post(&chops[ph_no]);
        sem_post(&chops[(ph_no+1)%5]);
        count++;
    }
    return 0;
}

void * eat2(void * arg){
    int ph_no = *(int *)arg;
    int count = 0;
    printf("%c preparing \n", ph[ph_no]);
    while(count < 20){
        sleep(rand() % 5);
        if(ph_no % 2){
            if(!sem_trywait(&chops[(ph_no+1)%5]))
                if(!sem_trywait(&chops[ph_no]))
                    printf("Ph-%c eating ... \n", ph[ph_no]);
                else sem_post(&chops[(ph_no+1)%5]);
        }else{
            if(!sem_trywait(&chops[ph_no]))
                if(!sem_trywait(&chops[(ph_no+1)%5]))
                    printf("Ph-%c eating ... \n", ph[ph_no]);
                else sem_post(&chops[ph_no]);
        }
        count++;
    }
    return 0;
}

int test(void * (*eat)(void * arg)){
    // printf("Test 1\n");
    for(int i = 0; i < 5; i++){
        sem_init(&chops[i], 0, 1);
    }

    int j = 0;
    pthread_t tid[5];
    int ph_no[5] = {0, 1, 2, 3, 4};
    for(j = 0; j < 5; j++){
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        // 这里不能用局部变量 j 来代替ph_no[j], 会出现奇怪的错误
        pthread_create(&tid[j], &attr, eat, (void *)&ph_no[j]);
    }

    void * status;
    for(int i = 0; i < 5; i++){
        pthread_join(tid[i], &status);
    }
    return 0;
}

int main(){
    printf("Project 1:\n");
    test(eat1);
    // printf("\n\nProject 2:\n");
    // test(eat2);
    return 0;
}